package com.bieber.tool;

import com.bieber.common.Constants;
import com.bieber.registry.Registry;
import com.bieber.registry.ZookeeperRegistry;
import com.bieber.registry.config.RegistryConfig;
import org.apache.commons.cli.*;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.List;
import java.util.Properties;
import java.util.StringTokenizer;

/**
 * Created by bieber on 2015/8/23.
 */
public class Main {

    private static Registry registry;

    private static  HelpFormatter hf;

    private static Options generateOptions(){
        Options options = new Options();
        Option option = new Option("st","shutdown",true,"shutdown some node(nodename)");
        options.addOption(option);
        option = new Option("ls","listnode",false,"list all registered nodes");
        options.addOption(option);
        option = new Option("h","help",false,"Get Help");
        options.addOption(option);
        option = new Option("vw","viewwrite",false,"view all node write status");
        options.addOption(option);
        option = new Option("i","interval",true,"auto do command in interval time(ms)");
        options.addOption(option);
        return options;
    }

    private static CommandLine parseCommandLine(CommandLineParser parser,String[] args,Options options){
        CommandLine commandLine = null;
        try {
            commandLine = parser.parse(options,args);
            if(commandLine.hasOption("h")){
                hf.printHelp(Constants.APP_NAME,options,true);
            }
        } catch (ParseException e) {
            hf.printHelp(Constants.APP_NAME,options,true);
        }
        return commandLine;
    }

    public static void main(String[] args){
        if(args.length<=0){
            throw new RuntimeException("must set config file path");
        }
        RegistryConfig registryConfig = new RegistryConfig();
        FileInputStream inputStream=null;
        try {
            inputStream=new FileInputStream(args[0]);
            Properties properties = new Properties();
            properties.load(inputStream);
            registryConfig.loadFromProperties(properties);
        } catch (Exception e) {
            Constants.COMMON_LOGGER.error("loading config from properties occur an exception",e);
        }finally {
            IOUtils.closeQuietly(inputStream);
        }
        registry = new ZookeeperRegistry(registryConfig);
        Options options = generateOptions();
        System.out.println("Please input command......");
        hf = new HelpFormatter();
        hf.setWidth(110);
        hf.printHelp(Constants.APP_NAME,options,true);
        BufferedReader  reader=  new BufferedReader(new InputStreamReader(System.in));
        String command=null;

        while(true){
            try {
                command=reader.readLine();
                if("exit".equals(command)){
                    break;
                }
                StringTokenizer tokenizer = new StringTokenizer(command);
                String[] params = new String[tokenizer.countTokens()];
                int i=0;
                while(tokenizer.hasMoreTokens()){
                    params[i]=tokenizer.nextToken();
                    i++;
                }
                CommandLine commandLine = parseCommandLine(new PosixParser(),params,options);
                if(commandLine.hasOption("st")){
                    registry.dynamicRegister(Constants.CONFIGURATOR_PATH + "/" + Constants.SHUTDOWN_COMMAND + "/"+commandLine.getOptionValue("st"));
                    System.out.println("shutdown node "+commandLine.getOptionValue("st"));
                }else if(commandLine.hasOption("ls")){
                    if(commandLine.hasOption("i")){
                        final int interval = Integer.parseInt(commandLine.getOptionValue("i"));
                        if(interval>0){
                            Thread t = new Thread(){
                                @Override
                                public void run() {
                                    while(true){
                                        try {
                                            viewNodes();
                                            Thread.sleep(interval);
                                        } catch (Exception e) {
                                            e.printStackTrace();
                                        }
                                    }
                                }
                            };
                            t.start();
                        }else{
                            viewNodes();
                        }
                    }else{
                        viewNodes();
                    }
                }else if(commandLine.hasOption("vw")){
                    if(commandLine.hasOption("i")){
                        final int interval = Integer.parseInt(commandLine.getOptionValue("i"));
                        if(interval>0){
                            Thread t = new Thread(){
                                @Override
                                public void run() {
                                    while(true){
                                        viewWriteStatus();
                                        try {
                                            Thread.sleep(interval);
                                        } catch (InterruptedException e) {
                                            e.printStackTrace();
                                        }
                                    }
                                }
                            };
                            t.start();
                        }else{
                            viewWriteStatus();
                        }
                    }else{
                        viewWriteStatus();
                    }
                }
            } catch (Exception e) {
                Constants.COMMON_LOGGER.warn("Read command occur an exception ",e);
                e.printStackTrace();
                break;
            }
        }
        System.exit(0);
    }

    private static synchronized void viewNodes() throws UnsupportedEncodingException {
        List<String> strings =registry.listChildren(Constants.NODES_PATH);
        if(strings.size()>0){
            for(String str:strings){
                System.out.println(URLDecoder.decode(str,"UTF-8"));
            }
        }else{
            System.out.println("not found any node");
        }
    }

    private static synchronized void viewWriteStatus(){
        List<String> strings = registry.listChildren(Constants.STATISTICS);
        if(strings.size()>0){
            System.out.println("Node               Filename            totalsize(Byte)       writesize(Byte)       completed(%)");
            StringBuffer stringBuffer = new StringBuffer();
            for(String str:strings){
                byte[] bytes = registry.getData(Constants.STATISTICS+"/"+str);
                if(bytes!=null){
                    String status =  new String(bytes);
                    String[] statusList = StringUtils.split(status,"->");
                    if(statusList.length<4){
                        continue;
                    }
                    stringBuffer.append(str).append("              ").append(statusList[0]).append("           ").append(statusList[1]).append("          ").append(statusList[2]).append("          ").append(statusList[3]);
                    System.out.println(stringBuffer.toString());
                }
                stringBuffer.setLength(0);
            }
        }else{
            System.out.println("not found any node");
        }
    }

}
